package viewbuilder.support

import org.springframework.util.ClassUtils

class ViewBuilderExecuter {

    def builder
    def classLoader
    def componentsLocation
    def componentsPackage

    def namespaces = [:]

    def execute(Class scriptClass, model, request, response) {
        Script script = (Script) scriptClass.newInstance();
        execete(script, model, request, response)
    }

    def execute(servletContext, String location, model, request, response) {        
        def input = servletContext.getResourceAsStream("/WEB-INF/${location}");
        def shell = new GroovyShell(classLoader)
        Script script = shell.parse(input.text)
        execute(script, model, request, response)
    }

    def execute(String scriptLocation, model, request, response) {
        def shell = new GroovyShell(classLoader)
        Script script = shell.parse(new File(scriptLocation))
        execute(script, model, request, response)
    }

    def execute(Script script, model, request, response) {
        def components = prepareComponents(request, response, null)
        addNamespacesTo(script)
        transferModel(script, model)
        addScopeProperties(script, request, response, null)
        script.run()
    }

    def addNamespacesTo(obj) {
        def meta = obj.metaClass
        namespaces.each { namespaceName, namespace ->
            meta[namespaceName] = namespace            
        }
//        components.each { component ->
//            meta[component.namespace] = component
//        }
    }

    //todo, replace with use of GroovyClassLoader
    def prepareComponents(request, response, servletContext) {
        def componentsDir = new File(componentsLocation)
        def components = []
        componentsDir.eachFileMatch(~/.*groovy/) {
            def className = it.name[0..<it.name.indexOf(".")]
            Class componentClass = ClassUtils.forName("${componentsPackage}.${className}", classLoader)
            println("---processing script: ${componentClass.name}")
            def component = componentClass.newInstance()
            addScopeProperties(component, request, response, servletContext)
            addClosuresToNamespace(component)
            components << component
        }
        components.each {
            addNamespacesTo(it)
        }
        return components
    }

    def addClosuresToNamespace(component) {
        def namespace = namespaces[component.namespace]
        if(!namespace) {
            namespace = new Expando()
            namespaces[component.namespace] = namespace
        }
        component.properties.each {name, property ->
            println("Adding ${name} to namespace ${component.namespace}")
            namespace[name] = property
        }
    }

    def addScopeProperties(obj, request, response, servletContext) {
        //todo, what happens if these properties already exist?
        def meta = obj.metaClass
        meta.request = request
        meta.session = request.session
        meta.response = response
        meta.servletContext = servletContext
        meta.builder = builder
    }

    def transferModel(script, model) {
        model.each {key, value ->
            script[key] = value
        }
        script.model = model
    }
}